// load-balancing-online---oj/oj_server/oj_login.hpp
#pragma once
#include <unordered_map>
#include <mutex>
#include <string>
#include <memory>
#include <ctime>
#include <cstdlib>
#include <iostream>
#include <cassert>
#include "../commen/mysql.hpp"
#include "../commen/log.hpp"

namespace ns_login
{
    using namespace ns_log;
    using namespace ns_mysql;

    // 用户结构体，包含用户的基本信息
    struct User
    {
        uint32_t uid;         // 用户ID
        std::string username; // 用户名
        std::string password; // 密码

        // 默认构造函数
        User() : uid(0), username(""), password("") {}

        // 带参数的构造函数
        User(uint32_t id, const std::string &user, const std::string &pass)
            : uid(id), username(user), password(pass) {}
    };

    // 会话结构体，包含会话的基本信息
    struct Session
    {
        std::string sessionId; // 会话ID
        uint32_t uid;          // 用户ID
        time_t createdAt;      // 创建时间戳
        time_t expiresAt;      // 过期时间戳

        // 默认构造函数
        Session() : sessionId(""), uid(0), createdAt(0), expiresAt(0) {}

        // 带参数的构造函数
        Session(const std::string &id, uint32_t userId)
            : sessionId(id), uid(userId), createdAt(time(nullptr)), expiresAt(createdAt + rand() % 3600) {} // 过期时间为创建时间加随机值
    };

    // 用户管理类，负责管理用户数据
    class UserManager
    {
    private:
        std::unordered_map<std::string, User> users_; // 存储用户的哈希表
        std::mutex mtx_;                              // 互斥锁，确保线程安全

        // 私有构造函数，防止外部实例化
        UserManager() {}

    public:
        // 获取用户管理类的单例实例
        static UserManager &getInstance()
        {
            static UserManager instance;
            return instance;
        }

        // 添加用户
        void addUser(const User &user)
        {
            std::lock_guard<std::mutex> lock(mtx_); // 锁定互斥量
            users_[user.username] = user;           // 将用户添加到哈希表
        }

        // 检查用户是否存在
        bool isUserExists(const std::string &username, const std::string &password, MYSQL *mysql)
        {
            std::lock_guard<std::mutex> lock(mtx_); // 锁定互斥量
            auto it = users_.find(username);        // 查找用户
            if (it != users_.end() && it->second.password != password)
            {
                LogMessage(Debug, "用户密码错误, user password: %s, db password: %s\n", password.c_str());
            }
            std::string sql = "select * from user where username = '" + username + "' and password = '" + password + "'";
            if (mysql_query(mysql, sql.c_str()) != 0)
            {
                LogMessage(Debug, "sql_err: %s, 登录失败\n", mysql_error(mysql));
                return false;
            }
            MYSQL_RES *res = mysql_store_result(mysql);
            if (res == nullptr)
            {
                LogMessage(Debug, "sql_error: %s, 查找用户出错\n", mysql_error(mysql));
                return false;
            }
            int n = mysql_num_rows(res);
            if (n != 1)
                return false;
            MYSQL_ROW row = mysql_fetch_row(res);
            uid_t uid_ = atoi(row[0]);
            std::string username_ = row[1];
            std::string password_ = row[2];
            User user(uid_, username_, password_);
            users_[username_] = user;
            return true;
        }

        bool registerUser(const std::string &username, const std::string &password, MYSQL *mysql)
        {
            std::lock_guard<std::mutex> lock(mtx_);
            std::string sql = "insert into user (username, password) values ('" + username + "', '" + password + "')";
            if (mysql_query(mysql, sql.c_str()) != 0)
            {
                LogMessage(Info, "sql_err: %s, 注册失败\n", mysql_error(mysql));
                return false;
            }
            sql.clear();
            sql = "select * from user where username = '" + username + "' and password = '" + password + "'";
            if (mysql_query(mysql, sql.c_str()) != 0)
            {
                LogMessage(Info, "sql_err: %s, 获取用户失败\n", mysql_error(mysql));
                return true;
            }
            MYSQL_RES *res = mysql_store_result(mysql);
            if (!res)
            {
                LogMessage(Info, "sql_err: %s, 获取用户失败\n", mysql_error(mysql));
                return true;
            }
            MYSQL_ROW row = mysql_fetch_row(res);
            uid_t uid_ = atoi(row[0]);
            std::string username_ = row[1];
            std::string password_ = row[2];
            User user(uid_, username_, password_);
            users_[username_] = user;
            return true;
        }

        // 获取用户信息，返回指向用户的指针
        User *getUser(const std::string &username)
        {
            std::lock_guard<std::mutex> lock(mtx_); // 锁定互斥量
            auto it = users_.find(username);
            if (it != users_.end())
                return &it->second; // 返回用户的地址
            return nullptr;         // 用户不存在
        }
    };

    // 会话管理类，负责管理用户会话
    class SessionManager
    {
    private:
        std::unordered_map<std::string, Session> sessions_; // 存储会话的哈希表
        std::mutex mtx_;                                    // 互斥锁，确保线程安全

        // 私有构造函数，防止外部实例化
        SessionManager() {}

    public:
        // 获取会话管理类的单例实例
        static SessionManager &getInstance()
        {
            static SessionManager instance;
            return instance;
        }

        // 创建新会话
        void createSession(const std::string &username, uint32_t uid)
        {
            std::lock_guard<std::mutex> lock(mtx_);                                         // 锁定互斥量
            std::string sessionId = std::to_string(time(nullptr)) + std::to_string(rand()); // 生成会话ID
            sessions_[sessionId] = Session(sessionId, uid);                                 // 创建并存储会话
        }

        // 检查会话是否有效
        bool isSessionValid(const std::string &sessionId)
        {
            std::lock_guard<std::mutex> lock(mtx_); // 锁定互斥量
            auto it = sessions_.find(sessionId);    // 查找会话
            if (it != sessions_.end())
            {
                return time(nullptr) < it->second.expiresAt; // 检查是否过期
            }
            return false; // 会话不存在
        }

        // 移除会话
        void removeSession(const std::string &sessionId)
        {
            std::lock_guard<std::mutex> lock(mtx_); // 锁定互斥量
            sessions_.erase(sessionId);             // 从哈希表中移除会话
        }
    };

    // 登录注册认证类
    class LoginRegisterAuthenticator
    {
    private:
        MYSQL *mysql_;

    public:
        LoginRegisterAuthenticator()
        {
            MySQLInit(mysql_);
            LogMessage(Debug, "数据库初始化成功\n");
        }

        // 登录功能
        bool login(const std::string &username, const std::string &password, const std::string &sessionId)
        {
            if (SessionManager::getInstance().isSessionValid(sessionId))
            {
                return true;
            }
            if (UserManager::getInstance().isUserExists(username, password, mysql_)) // 验证用户
            {
                // 使用指针访问 uid
                auto uid = UserManager::getInstance().getUser(username)->uid; // 获取用户ID
                SessionManager::getInstance().createSession(username, uid);   // 创建会话
                return true;                                                  // 登录成功
            }
            return false; // 登录失败
        }

        // 注册功能可以在这里实现
        // 查看该用户是否存在，存在则注册失败
        bool Register(const std::string &username, const std::string &password)
        {
            if (UserManager::getInstance().isUserExists(username, password, mysql_))
            {
                LogMessage(Info, "用户已存在，注册失败\n");
                return false;
            }
            else
            {
                if (!UserManager::getInstance().registerUser(username, password, mysql_))
                {
                    LogMessage(Info, "注册用户失败\n");
                    return false;
                }
                LogMessage(Info, "注册用户成功\n");
                return true;
            }
        }
    };
}